package com.siao.loader
{
	import com.siao.events.BytesEvent;
	
	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLRequest;
	import flash.net.URLStream;
	import flash.utils.ByteArray;
	
	[Event(name="open", type="com.siao.events.BytesEvent")]
	
	[Event(name="complete", type="com.siao.events.BytesEvent")]
	
	[Event(name="error", type="com.siao.events.BytesEvent")]
	
	[Event(name="progress", type="flash.events.ProgressEvent")]
	
	/**
	 * 二进制加载字节流
	 * @author SiaoLeon
	 */
	public class BytesStream extends EventDispatcher
	{
		// -------------------------------------------------------------------------------------------------------- 静态常量
		
		// -------------------------------------------------------------------------------------------------------- 静态变量
		
		// -------------------------------------------------------------------------------------------------------- 静态方法
		
		// -------------------------------------------------------------------------------------------------------- 静态函数
		
		// -------------------------------------------------------------------------------------------------------- 属性
		
		private var _data:ByteArray;
		
		/**
		 * 字节数据
		 * @return
		 */
		public function get data():ByteArray
		{
			return _data;
		}
		
		/**
		 * 表示此 BytesStream 对象目前是否已连接。
		 * @return
		 */
		public function get connected():Boolean
		{
			return this.stream.connected;
		}
		
		// -------------------------------------------------------------------------------------------------------- 变量
		
		private var stream:URLStream;
		
		// -------------------------------------------------------------------------------------------------------- 构造
		
		/**
		 * 构造函数
		 */
		public function BytesStream()
		{
			this.stream = new URLStream();
		}
		
		// -------------------------------------------------------------------------------------------------------- 方法
		
		/**
		 * 开始下载 request 参数中指定的 URL
		 * @param request
		 */
		public function load(request:URLRequest):void
		{
			this.registerStreamEventListener();
			this.stream.load(request);
		}
		
		/**
		 * 立即关闭该流并取消下载操作。
		 */
		public function close():void
		{
			if (this.stream.connected)
			{
				this.stream.close();
			}
			this.removeStreamEventListener();
		}
		
		// -------------------------------------------------------------------------------------------------------- 函数
		
		/**
		 * 注册二进制加载流的事件侦听
		 */
		private function registerStreamEventListener():void
		{
			this.stream.addEventListener(Event.OPEN, onOpen);
			this.stream.addEventListener(ProgressEvent.PROGRESS, onProgress);
			this.stream.addEventListener(Event.COMPLETE, onComplete);
			this.stream.addEventListener(IOErrorEvent.IO_ERROR, onError);
			this.stream.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
		}
		
		/**
		 * 移除二进制加载流的事件侦听
		 */
		private function removeStreamEventListener():void
		{
			this.stream.removeEventListener(Event.OPEN, onOpen);
			this.stream.removeEventListener(ProgressEvent.PROGRESS, onProgress);
			this.stream.removeEventListener(Event.COMPLETE, onComplete);
			this.stream.removeEventListener(IOErrorEvent.IO_ERROR, onError);
			this.stream.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
		}
		
		/**
		 * 二进制加载流打开时
		 * @param event
		 */
		private function onOpen(event:Event):void
		{
			this._data = new ByteArray();
			this.dispatchEvent(new BytesEvent(BytesEvent.OPEN));
		}
		
		/**
		 * 二进制加载流进度时
		 * @param event
		 */
		private function onProgress(event:ProgressEvent):void
		{
			this.save();
			this.dispatchEvent(event);
		}
		
		/**
		 * 二进制加载流完成时
		 * @param event
		 */
		private function onComplete(event:Event):void
		{
			this.save();
			this.close();
			this.dispatchEvent(new BytesEvent(BytesEvent.COMPLETE));
		}
		
		/**
		 * 二进制加载流错误时
		 * @param event
		 */
		private function onError(event:ErrorEvent):void
		{
			this.close();
			this.dispatchEvent(new BytesEvent(BytesEvent.ERROR));
		}
		
		/**
		 * 保存已加载的二进制数据
		 */
		private function save():void
		{
			if (this.stream.bytesAvailable > 0)
			{
				var len:Number = this._data.length;
				this.stream.readBytes(this._data, len, this.stream.bytesAvailable);
			}
		}
	
	}
}
